package pd_common

import (
	"log"
	"net"
	"sync"
	"time"

	"github.com/gorilla/websocket"
	"github.com/pion/transport/v2/packetio"
)

var _ net.PacketConn = (*WebSocketPacketConn)(nil)

type WebSocketPacketConn struct {
	conn  *websocket.Conn
	mutex sync.Mutex

	buff *packetio.Buffer
}

func NewWebSocketPacketConn(conn *websocket.Conn) *WebSocketPacketConn {
	tis := &WebSocketPacketConn{
		conn: conn,
		buff: packetio.NewBuffer(),
	}

	go func() {
		defer func() {
			_ = tis.buff.Close()
		}()

		for {
			tt, data, err := tis.conn.ReadMessage()
			if err != nil {
				log.Printf("ReadFrom err: %v", err)
				return
			}

			ok := false
			switch tt {
			case websocket.BinaryMessage:
				ok = true
				break
			default:
				log.Printf("ReadFrom type: %v", tt)
			}
			if !ok {
				continue
			}

			_, _ = tis.buff.Write(data)
		}
	}()

	return tis
}

func (tis *WebSocketPacketConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
	n, err = tis.buff.Read(p)
	if err != nil {
		log.Printf("ReadFrom err: %v", err)
		return 0, nil, err
	}

	log.Printf("ReadFrom  %v %v", n, len(p))

	return n, &net.UDPAddr{
		IP:   net.ParseIP("127.0.0.1"),
		Port: 456,
	}, nil
}

func (tis *WebSocketPacketConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
	tis.mutex.Lock()
	defer tis.mutex.Unlock()

	log.Printf("WriteTo  %v", len(p))

	err = tis.conn.WriteMessage(websocket.BinaryMessage, p)
	return len(p), err
}

func (tis *WebSocketPacketConn) WritePingMessage() {
	tis.mutex.Lock()
	defer tis.mutex.Unlock()

	_ = tis.conn.WriteControl(websocket.PingMessage, []byte{}, time.Now().Add(time.Second))
}

func (tis *WebSocketPacketConn) Close() error {
	return nil
}

func (tis *WebSocketPacketConn) LocalAddr() net.Addr {
	return &net.UDPAddr{
		IP:   net.ParseIP("127.0.0.1"),
		Port: 855,
	}
}

func (tis *WebSocketPacketConn) SetDeadline(t time.Time) error {
	return nil
}

func (tis *WebSocketPacketConn) SetReadDeadline(t time.Time) error {
	return nil
}

func (tis *WebSocketPacketConn) SetWriteDeadline(t time.Time) error {
	return nil
}
